﻿// ===============================================================================
//  Copyright © ymind.net. All rights reserved .
//  官方网站：http://ymind.net/
//  版权所有：彦铭工作室 老陈出品
// ===============================================================================

using System;
using System.Collections;
using System.Xml;
using Lcsoft.UrlRewriter.Actions;
using Lcsoft.UrlRewriter.Conditions;
using Lcsoft.UrlRewriter.Configuration;
using Lcsoft.UrlRewriter.Utilities;

namespace Lcsoft.UrlRewriter.Parsers
{
	/// <summary>
	///  解析 &lt;set&gt; 标记，并提供设置 Cookie 的能力。
	/// </summary>
	public abstract class RewriteActionParserBase : IRewriteActionParser
	{
		#region IRewriteActionParser Members

		/// <summary>
		/// 获取动作名。
		/// </summary>
		public abstract string Name { get; }

		/// <summary>
		/// 获取一个值，该值指示当前动作是否允许嵌套动作。
		/// </summary>
		public abstract bool AllowsNestedActions { get; }

		/// <summary>
		/// 获取一个值，该值指示当前动作是否允许包含 Attribute 属性。
		/// </summary>
		public abstract bool AllowsAttributes { get; }

		/// <summary>
		/// 执行地址重写动作解析。
		/// </summary>
		/// <param name="node">包含要解析的动作信息的。</param>
		/// <param name="config">地址重写配置信息。</param>
		/// <returns>返回地址重写动作的实例。</returns>
		public abstract IRewriteAction Parse(XmlNode node, RewriterConfiguration config);

		#endregion

		/// <summary>
		/// 解析与当前动作相关的先决条件。
		/// </summary>
		/// <param name="node">包含地址重写动作信息的 <see cref="XmlNode"/>。</param>
		/// <param name="conditions">先决条件的集合。</param>
		/// <param name="negative">是否做负向匹配。</param>
		/// <param name="config">地址重写配置信息。</param>
		protected void ParseConditions(XmlNode node, IList conditions, bool negative, RewriterConfiguration config)
		{
			if (config == null) throw new ArgumentNullException("config");
			if (node == null) throw new ArgumentNullException("node");

			if (conditions == null) throw new ArgumentNullException("conditions");

			foreach (var parser in config.ConditionParsers)
			{
				var condition = parser.Parse(node);

				if (condition == null) continue;
				if (negative) condition = new NegativeCondition(condition);

				conditions.Add(condition);
			}

			var childNode = node.FirstChild;

			while (childNode != null)
			{
				if (childNode.NodeType == XmlNodeType.Element && childNode.LocalName == Constants.ElementAnd)
				{
					this.ParseConditions(childNode, conditions, negative, config);

					var childNode2 = childNode.NextSibling;

					node.RemoveChild(childNode);

					childNode = childNode2;

					continue;
				}

				childNode = childNode.NextSibling;
			}
		}
	}
}
